+2005-09-27 Øyvind Kolås <pippin@gimp.org>
+
+ * babl/babl-classes.h: Added time consumption instrumentation to
+ BablFish.
+ * babl/babl-fish-path.c: (babl_fish_path), (babl_fish_path_process):
+ intialization of instrumentation data.
+ * babl/babl-fish-stats.c: (table_destination_each), (each_conv),
+ (conversions), (babl_fish_stats): Output timing data, as well as a
+ list of all conversions with the obviously bad ones marked in red.
+ * babl/babl-internal.c: (babl_process): update instrumentation.
+ * babl/babl-introspect.c: (conversion_introspect): only query error
+ from conversions where that is legal.
+ * babl/babl-util.c: changed from msecs to nsecs (might be some more
+ places in the code to change names of variables.)
+ * extensions/gggl.c: (conv_gF_gaF), (conv_gF_rgbF), (conv_rgbF_gF),
+ (conv_rgbaF_rgb8): Changes to increase sanity.
+
2005-09-27 Øyvind Kolås <pippin@gimp.org>
* tests/srgb_to_lab_u8.c: (test): renamed format (srgb -> R'G'B' u8)
int *stride;
} BablImage;
-/* BablFish base class, the user of babl is just requesting a
- * conversion, after that an appropriate species of fish is
- * constructed to handle the request.
- *
- * TODO:
- * * implement
+/* BablFish, common base class for various fishes.
*/
typedef struct
{
BablInstance instance;
union Babl *source;
union Babl *destination;
- int processings;
- long pixels;
- double error;
+
+ double error; /* the amount of noise introduced by the fish */
+
+ /* instrumentation */
+ int processings; /* number of times the fish has been used */
+ long pixels; /* number of pixels translates */
+ long msecs; /* msecs spent within this fish */
} BablFish;
/* BablFishSimple is the simplest type of fish, wrapping a single
* conversion function, (note this might not be the optimal chosen
* conversion even if it exists)
+ *
+ * TODO: exterminate
*/
typedef struct
{
/* BablFishPath is a combination of registered conversions, both
- * from the reference types / model conversions, and optimized paths.
+ * from the reference types / model conversions, and optimized format to
+ * format conversion.
*
* This is the most advanced scheduled species of fish, some future
- * version of babl might even be evovling combined fishes in a background
- * thread, based on profiled usage. For this to work in a future version
- * transmogrification between the fish classes would be used.
+ * version of babl might even be evovling path fishes in a background
+ * thread, based on the fish instrumentation. For this to work in a future
+ * version transmogrification between the fish classes would be used.
*/
typedef struct
{
BablFish fish;
- double cost;
- double loss;
+ double cost; /* number of ticks *10 + chain_length */
+ double loss; /* error introduced */
+
BablConversion *conversion[BABL_HARD_MAX_PATH_LENGTH];
int conversions;
} BablFishPath;
-/* BablFishReference on the double versions of conversions
- * that are required to exist for maximum sanity.
+/* BablFishReference
*
* A BablFishReference is not intended to be fast, thus the algorithm
- * encoded can use a multi stage approach, where some of the stages could
- * be completely removed for optimization reasons.
- *
- * This is not the intention of the "BablFishReference factory", it's
- * implementation is meant to be kept as small as possible wrt logic.
+ * encoded can use a multi stage approach, based on the knowledge babl
+ * has encoded in the pixel formats.
*
* One of the contributions that would be welcome are new fish factories.
*
* TODO:
- * * cache the looked up conversions, removing all overhead but the
- * actual conversions.
* * make optimal use of a single allocation containing enough space
- * for the maximum amount of memory needed in to adjecant buffers
+ * for the maximum amount of memory needed in two adjecant buffers
* at any time.
*/
typedef struct
typedef struct
{
- BablInstance instance; /* path to .so / .dll is stored in instance name */
+ BablInstance instance; /* path to .so / .dll is stored in instance name */
void *dl_handle;
void (*destroy) (void);
} BablExtension;
babl->fish.processings = 0;
babl->fish.pixels = 0;
+ babl->fish.msecs = 0;
babl->fish.error = 200000;
babl->fish_path.cost = 200000;
void *destination,
long n)
{
+ long ret;
+
babl_assert (source);
babl_assert (destination);
-
- return chain_process (babl->fish_path.conversion,
- babl->fish_path.conversions,
- source,
- destination,
- n);
+
+ ret = chain_process (babl->fish_path.conversion,
+ babl->fish_path.conversions,
+ source,
+ destination,
+ n);
+
+ return ret;
}
fprintf (output_file, "<h3><span class='g'>path</span> %s <span class='g'>to</span> %s</h3>", source->instance.name, destination->instance.name);
if (fish->fish.processings > 0)
{
+ fprintf (output_file, "<span class='g'>msecs:</span>%li<br/>", fish->fish.msecs);
fprintf (output_file, "<span class='g'>Processings:</span>%i<br/>", fish->fish.processings);
fprintf (output_file, "<span class='g'>Pixels:</span>%li<br/>", fish->fish.pixels);
}
if (fish->fish.processings > 0)
{
+ fprintf (output_file, "<span class='g'>msecs:</span>%li<br/>", fish->fish.msecs);
fprintf (output_file, "<span class='g'>Processings:</span>%i<br/>", fish->fish.processings);
fprintf (output_file, "<span class='g'>Pixels:</span>%li<br/>", fish->fish.pixels);
}
return 0;
}
+static int
+each_conv (Babl *babl,
+ void *data)
+{
+ double error, cost;
+
+ if (BABL(babl->conversion.source)->class_type != BABL_FORMAT)
+ return 0;
+
+ error = babl_conversion_error (&babl->conversion);
+ cost = babl_conversion_cost (&babl->conversion);
+
+ if (error>0.01)
+ {
+ fprintf (output_file, "<dt style='background-color: #fcc;'>%s</dt>", babl->instance.name);
+ fprintf (output_file, "<dd style='background-color: #fcc;'>");
+ }
+ else
+ {
+ fprintf (output_file, "<dt>%s</dt><dd>", babl->instance.name);
+ }
+ fprintf (output_file, "<em>error:</em> %f <em>cost:</em> %4.0f <em>processings:</em> %i <em>pixels:</em> %li", error, cost,
+ babl->conversion.processings, babl->conversion.pixels);
+ fprintf (output_file, "</dd>");
+
+ return 0;
+}
+
+static void
+conversions ()
+{
+ fprintf (output_file, "<h2>Conversions</h2><dl>\n");
+ babl_conversion_each (each_conv, NULL);
+ fprintf (output_file, "</dl>\n");
+}
+
void
babl_fish_stats (FILE *file)
{
fprintf (output_file, "<div style='height:20em'></div>\n");
+ conversions ();
+
fprintf (output_file, "</body></html>\n");
}
babl->class_type == BABL_FISH_PATH ||
babl->class_type == BABL_FISH_SIMPLE)
{
+ long ret;
+ long ticks = babl_ticks ();
+ ret = babl_fish_process (babl, source, destination, n);
+
+ ticks -= babl_ticks();
+ ticks *= -1;
+
+ babl->fish.msecs += ticks;
babl->fish.processings++;
- babl->fish.pixels += n;
- return babl_fish_process (babl, source, destination, n);
+ babl->fish.pixels += ret;
+ return ret;
}
babl_fatal ("eek");
{
babl_log ("\t\tprocessings:%i pixels:%li",
babl->conversion.processings, babl->conversion.pixels);
- babl_log ("\t\tcost: %i error: %f",
- babl_conversion_cost (&babl->conversion),
- babl_conversion_error (&babl->conversion));
+ if (BABL(babl->conversion.source)->class_type == BABL_FORMAT)
+ {
+ babl_log ("\t\terror: %f", babl_conversion_error (&babl->conversion));
+ }
}
static void
static struct timeval start_time;
static struct timeval measure_time;
-#define msecs(time) ((time.tv_sec-start_time.tv_sec)*1000 + time.tv_usec/1000)
+#define msecs(time) ((time.tv_sec-start_time.tv_sec)*10000000 + time.tv_usec)
static void
init_ticks (void)
long n=samples;
while (n--)
{
- *(int *) dst = (*(int *) src);
+ *(float *) dst = (*(float *) src);
dst += 4;
src += 4;
*(float *) dst = 1.0;
for (c = 0; c < 3; c++)
{
- (*(int *) dst) = (*(int *) src);
+ (*(float *) dst) = (*(float *) src);
dst += 4;
}
src += 4;
sum += (*(float *) src);
src += 4;
}
- sum /= 3;
+ sum /= 3.0;
(*(float *) dst) = sum;
dst += 4;
}
for (c = 0; c < 3; c++)
{
- *(unsigned char *) dst = rint ((*(float *) src) * 255.0);
+ int val=rint ((*(float *) src) * 255.0);
+ if (val<0)
+ *(unsigned char *) dst = 0;
+ else if (val>255)
+ *(unsigned char *) dst = 255;
+ else
+ *(unsigned char *) dst = val;
dst += 1;
src += 4;
}